package com.vis.mybatisflex.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.vis.mybatisflex.domain.excel.CcAllDataRead1Excel;
import com.vis.mybatisflex.domain.excel.CcDataWriteEndExcel;
import com.vis.mybatisflex.domain.excel.CcDataWriteZjExcel;
import com.vis.mybatisflex.domain.excel.CcHighExcel;
import com.vis.mybatisflex.service.CcExcelServiceV02;
import com.vis.mybatisflex.util.StringKit;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

/**
 * @author 王师傅
 * @since 2025-11-17
 */
@Slf4j
@Service
public class CcExcelServiceV02Impl implements CcExcelServiceV02 {

    /**
     * 中文分号
     * 英文分号
     * 换行符
     * 窗口 + 顿号
     * 窗口 + 空格 + 顿号
     * 窗口 + 中文逗号
     * 窗口 + 英文逗号
     * 服务中心 + 顿号
     * 派出所 + 顿号
     */
    private static final List<String> RULE_LIST = Arrays.asList(
            "\n",
            "；",
            ";",
            "窗口、",
            "窗口 、",
            "窗口；",
            "窗口;",
            "服务中心、",
            "派出所、"
    );

    private static final String VERSION = "V0.2";
    private static final String FILE_TYPE = "xlsx";
    private static final String FILE_BASE = "C:\\Users\\Administrator\\Desktop\\ccexcel\\";

    private static final String _1_read_write_file_path = FILE_BASE + "_1_read_write_file_path_" + VERSION + "." + FILE_TYPE;

    private static final String _2_set_data_file_path = FILE_BASE + "_2_set_data_file_path_" + VERSION + "." + FILE_TYPE;

    private static final String _3_1_0_not_split_path = FILE_BASE + "_3_1_0_not_split_path_" + VERSION + "." + FILE_TYPE;

    private static final String _3_1_0_not_split_path_中文 = FILE_BASE + "_a_过滤掉的数据_村（社区）级_" + VERSION + "." + FILE_TYPE;

    private static final String _3_1_1_need_split_path = FILE_BASE + "_3_1_1_need_split_path_" + VERSION + "." + FILE_TYPE;

    private static final String _3_2_split_error_path = FILE_BASE + "_3_2_split_error_path_" + VERSION + "." + FILE_TYPE;
    private static final String _3_2_split_error_path_中文 = FILE_BASE + "_b_拆分失败的数据_" + VERSION + "." + FILE_TYPE;

    private static final String _3_2_need_split_path = FILE_BASE + "_3_2_need_split_path_" + VERSION + "." + FILE_TYPE;

    private static final String _4_1_split_ok_path = FILE_BASE + "_4_1_split_ok_path_" + VERSION + "." + FILE_TYPE;
    private static final String _4_1_split_ok_path_中文 = FILE_BASE + "_c_拆分完成后的数据_" + VERSION + "." + FILE_TYPE;

    private static final String _5_1_sum_end_path = FILE_BASE + "_5_1_sum_end_path_" + VERSION + "." + FILE_TYPE;
    private static final String _5_1_sum_end_path_中文 = FILE_BASE + "_d_汇总所有数据_最终结果_" + VERSION + "." + FILE_TYPE;


    /**
     * 解析数据，转存数据
     */
    @Override
    public void _1_ReadWrite1() throws Exception {
        File file = new File("C:\\Users\\Administrator\\Desktop\\ccexcel\\政务高频事项库V0.1.xlsx");
        System.out.println(file.getAbsolutePath());
        HashSet<String> allHighName = new HashSet<>();
        ArrayList<CcDataWriteZjExcel> objects = new ArrayList<>();

        // 这里默认读取第一个sheet
        EasyExcel.read(new FileInputStream(file), CcHighExcel.class, new ReadListener<CcHighExcel>() {
            @Override
            public void invoke(CcHighExcel data, AnalysisContext context) {
                //                log.info("data : {}", JSONObject.toJSONString(data));
                String ywSxName = data.getYwSxName();
                //                log.info"ywSxName : {}", ywSxName);
                allHighName.add(ywSxName);
            }

            @SneakyThrows
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                log.info("需要解析主项:一共 {} 条", allHighName.size());

                File file = new File("C:\\Users\\Administrator\\Desktop\\ccexcel\\政务完整事项库V0.1.xlsx");
                // 这里默认读取第一个sheet
                EasyExcel.read(new FileInputStream(file), CcAllDataRead1Excel.class, new ReadListener<CcAllDataRead1Excel>() {


                    @Override
                    public void invoke(CcAllDataRead1Excel data, AnalysisContext context) {
                        //
                        if (allHighName.contains(data.get业务办理项名称())) {
                            CcDataWriteZjExcel ccDataWriteZjExcel = new CcDataWriteZjExcel();
                            ccDataWriteZjExcel.set区划名称(data.get区划名称());
                            ccDataWriteZjExcel.set上级区划名称(data.get上级区划名称());
                            ccDataWriteZjExcel.set地区层级(data.get地区层级());
                            ccDataWriteZjExcel.set办理地点(data.get办理地点());
                            ccDataWriteZjExcel.set业务主项(data.get主项名称());
                            ccDataWriteZjExcel.set业务办理项目名称(data.get业务办理项名称());
                            objects.add(ccDataWriteZjExcel);
                        }
                        //                        a += 1;
                        //                        log.info("data : {}", JSONObject.toJSONString(data));
                    }

                    @SneakyThrows
                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        EasyExcel.write(_1_read_write_file_path, CcDataWriteZjExcel.class).sheet("初始筛选数据").doWrite(objects);
                        System.out.println("数据处理完成 条数：" + objects.size());
                        System.out.println("path：" + _1_read_write_file_path);
                        //                        System.out.println(JSONObject.toJSONString(objects.get(0)));
                        //                        System.out.println();
                        //                        System.out.println(JSONObject.toJSONString(objects.get(1)));
                        //                        System.out.println();
                        //                        System.out.println(JSONObject.toJSONString(objects.get(2)));
                        //                        System.out.println();
                        //                        System.out.println(JSONObject.toJSONString(objects.get(3)));
                        //                        System.out.println();
                        //                        System.out.println(JSONObject.toJSONString(objects.get(4)));
                    }
                }).sheet().doRead();

            }
        }).sheet().doRead();

    }

    /**
     * 设置数据
     */
    public void _2_SetData() throws Exception {
        ArrayList<CcDataWriteZjExcel> allData = new ArrayList<>();

        EasyExcel.read(_1_read_write_file_path, CcDataWriteZjExcel.class, new ReadListener<CcDataWriteZjExcel>() {
            @Override
            public void invoke(CcDataWriteZjExcel data, AnalysisContext context) {
                allData.add(data);
            }

            @SneakyThrows
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                log.info("设置数据:一共 {} 条", allData.size());
                allData.forEach(this::setByDqcj);

                //写数据
                EasyExcel.write(_2_set_data_file_path, CcDataWriteZjExcel.class).sheet("区域数据+地点数据").doWrite(allData);
                System.out.println("_1_filePath：" + _1_read_write_file_path);
                System.out.println("_2_set_data_file_path：" + _2_set_data_file_path);
                System.out.println("数据处理完成 条数：" + allData.size());
            }

            //设置区域数据，地点数据
            private void setByDqcj(CcDataWriteZjExcel e) {
                var quHua = e.get区划名称();
                var quShangJi = e.get上级区划名称();
                var dqCengJi = e.get地区层级();
                var blDiDian = e.get办理地点();
                var quSj1 = "";
                var quSj2 = "";
                var quSjSize = 0;
                try {
                    quSj1 = quShangJi.split(",")[0];
                    quSj2 = quShangJi.split(",")[1];
                    quSjSize = quShangJi.split(",").length;
                } catch (Exception ignore) {
//                    System.out.println(JSONObject.toJSONString(e));
                }

                //清除垃圾办理地址
                if (StringKit.isNotBlank(blDiDian)) {
                    for (int i = 0; i < 20; i++) {
                        //1. 1、（1）
                        blDiDian = blDiDian.replace("（" + i + "）", "");
                        blDiDian = blDiDian.replace(i + ".", "");
                        blDiDian = blDiDian.replace(i + "、", "");
                    }
                }

                switch (dqCengJi) {
                    case "村（社区）级":
                        //		（1）四段 会展街道,长春经济技术开发区,长春市,吉林省
                        //                        区域：取第二个 长春经济技术开发区
                        //                        1级办理名称：取第一个 会展街道
                        //                        1级办理地点：空
                        //                        2级办理名称：就是区划名称 - 芜湖社区
                        //                        2级办理地点：就是实际地址，拆分
                        if (quSjSize == 4) {
                            e.set区域(quSj2);

                            e.set一级办理名称(quSj1);
                            e.set一级办理地点(null);

                            e.set二级办理名称(quHua);
                            e.set二级办理地点(blDiDian);

                            e.set区域别名("村");
                        }
                        // 		                （2）三段：南关区,长春市,吉林省
                        //                        区域：取第一个
                        //                        1级办理名称：取第一个
                        //                        1级办理地点：取第一个
                        //                        2级办理名称：就是区划名称 - 国信社区
                        //                        2级办理地点：就是实际地址，拆分
                        if (quSjSize == 3) {
                            e.set区域(quSj1);

                            e.set一级办理名称(quSj1);
                            e.set一级办理地点(quSj1);

                            e.set二级办理名称(quHua);
                            e.set二级办理地点(blDiDian);

                            e.set区域别名("村");
                        }
                        break;

                    case "市级":
                        //                        市级
                        //                        区域:取区划名称
                        //                        1级办理名称：就是区划名称 - 长春新区
                        //                        1级办理地点：就是实际地址，拆分
                        //                        2级办理名称：空
                        //                        2级办理地点：空
                        e.set区域(quHua);

                        e.set一级办理名称(quHua);
                        e.set一级办理地点(blDiDian);

                        e.set二级办理名称(null);
                        e.set二级办理地点(null);

                        e.set区域别名("市");
                        break;

                    case "县级":
//                        区域:就是区划名称 - 朝阳区
//                        1级办理名称：就是区划名称 - 朝阳区
//                        1级办理地点：就是实际地址，拆分
//                        2级办理名称：空
//                        2级办理地点：空

                        e.set区域(quHua);

                        e.set一级办理名称(quHua);
                        e.set一级办理地点(blDiDian);

                        e.set二级办理名称(null);
                        e.set二级办理地点(null);

                        e.set区域别名("县");
                        break;

                    case "镇（乡、街道）级":
                        //                        区域：上级区划名称，取第一个
                        //                        1级办理名称：就是区划名称 - 林园街道
                        //                        1级办理地点：就是实际地址，拆分
                        //                        2级办理名称：空
                        //                        2级办理地点：空

                        e.set区域(quSj1);

                        e.set一级办理名称(quHua);
                        e.set一级办理地点(blDiDian);

                        e.set二级办理名称(null);
                        e.set二级办理地点(null);

                        e.set区域别名("镇");

                }


            }
        }).sheet().doRead();

    }

    /**
     * 不需要拆分的数据
     */
    public void _3_NotSplit() throws Exception {
        ArrayList<CcDataWriteZjExcel> allData = new ArrayList<>();
        System.out.println("处理文件 " + _2_set_data_file_path);

        // 这里默认读取第一个sheet
        EasyExcel.read(_2_set_data_file_path, CcDataWriteZjExcel.class, new ReadListener<CcDataWriteZjExcel>() {
            @Override
            public void invoke(CcDataWriteZjExcel data, AnalysisContext context) {
                allData.add(data);
            }

            @SneakyThrows
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                log.info("数据项:一共 {} 条", allData.size());
                log.info("数据项:拆分规则 中英文分号");

                ArrayList<Object> notSplit = new ArrayList<>();
                ArrayList<Object> needSplit = new ArrayList<>();
                for (var a : allData) {
                    String 办理地点 = a.get办理地点();
                    if (StringKit.isBlank(办理地点)) {
                        System.out.println("事项地址缺失：" + JSONObject.toJSONString(a));
                    }
                    var dqCengJi = a.get地区层级();
                    if ("村（社区）级".equals(dqCengJi)) {
                        notSplit.add(a);
                    } else {
                        needSplit.add(a);
                    }
                }
                EasyExcel.write(_3_1_0_not_split_path, CcDataWriteEndExcel.class).sheet("不需要拆分的数据").doWrite(JSONArray.parse(JSONArray.toJSONString(notSplit)).toJavaList(CcDataWriteEndExcel.class));
                EasyExcel.write(_3_1_0_not_split_path_中文, CcDataWriteEndExcel.class).sheet("不需要拆分的数据").doWrite(JSONArray.parse(JSONArray.toJSONString(notSplit)).toJavaList(CcDataWriteEndExcel.class));

                EasyExcel.write(_3_1_1_need_split_path, CcDataWriteEndExcel.class).sheet("需要继续拆分的数据").doWrite(JSONArray.parse(JSONArray.toJSONString(needSplit)).toJavaList(CcDataWriteEndExcel.class));
                log.info("处理完成");
                log.info("共计数据 :{}", needSplit.size() + notSplit.size());
                log.info("需要继续拆分的数据 :{}", needSplit.size());
                log.info("不需要拆分的数据 过滤掉的数据_村（社区）级 :{}", notSplit.size());
            }
        }).sheet().doRead();

    }

    /**
     * 进一步区分，可以拆 和 不可以拆
     */
    public void _3_2_ErrorAndSplit() throws Exception {
        ArrayList<CcDataWriteEndExcel> allData = new ArrayList<>();
        System.out.println("处理文件 " + _3_1_1_need_split_path);

        // 这里默认读取第一个sheet
        EasyExcel.read(_3_1_1_need_split_path, CcDataWriteEndExcel.class, new ReadListener<CcDataWriteEndExcel>() {
            @Override
            public void invoke(CcDataWriteEndExcel data, AnalysisContext context) {
                allData.add(data);
            }

            @SneakyThrows
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                log.info("数据项:一共 {} 条", allData.size());
                ArrayList<Object> splitError = new ArrayList<>();
                ArrayList<Object> splitOk = new ArrayList<>();

                for (var a : allData) {
                    String 一级办理地点 = a.get一级办理地点();
                    String 二级办理地点 = a.get二级办理地点();
                    String 办理地点 = StringKit.isNotBlank(一级办理地点) ? 一级办理地点 : 二级办理地点;

                    if (StringKit.isBlank(办理地点)) {
                        System.out.println("事项地址缺失：" + JSONObject.toJSONString(a));
                        splitError.add(a);
                        continue;
                    }

                    // 是否需要拆分
                    var hasSplit = false;
                    for (var rule : RULE_LIST) {
                        if (办理地点.contains(rule)) {
                            hasSplit = true;
                            break;
                        }
                    }

                    // 需要拆的数据
                    if (hasSplit) {
                        splitOk.add(a);
                    }
                    //可能存在问题
                    else {
                        splitError.add(a);
                    }

                }

                log.info("共计数据 :{}", allData.size());
                log.info("拆分失败-人工检查 :{}", splitError.size());
                log.info("可以拆分的数据 :{}", splitOk.size());

                EasyExcel.write(_3_2_split_error_path, CcDataWriteEndExcel.class).sheet("拆分失败-人工检查").doWrite(splitError);
                EasyExcel.write(_3_2_split_error_path_中文, CcDataWriteEndExcel.class).sheet("拆分失败-人工检查").doWrite(splitError);
                EasyExcel.write(_3_2_need_split_path, CcDataWriteEndExcel.class).sheet("可以拆分的数据").doWrite(splitOk);
            }
        }).sheet().doRead();

    }

    /**
     * 处理可以拆分的数据
     */
    public void _4_Split() throws Exception {
        ArrayList<CcDataWriteEndExcel> allData = new ArrayList<>();
        System.out.println("处理文件 " + _3_2_need_split_path);
        // 这里默认读取第一个sheet
        EasyExcel.read(_3_2_need_split_path, CcDataWriteEndExcel.class, new ReadListener<CcDataWriteEndExcel>() {
            @Override
            public void invoke(CcDataWriteEndExcel data, AnalysisContext context) {
                allData.add(data);
            }

            @SneakyThrows
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                log.info("数据项:一共 {} 条", allData.size());

                //TODO-规则-做活
                log.info("数据项:拆分规则 【中文分号 英文分号 换行 窗口、 窗口 、  服务中心、  派出所、】");

                ArrayList<CcDataWriteEndExcel> result = allData;
                for (var rule : RULE_LIST) {
                    result = chai(result, rule);
                }
//                ArrayList<CcDataWriteEndExcel> chai = chai(allData, "\n");
//                ArrayList<CcDataWriteEndExcel> chai1 = chai(chai, "；");//中文
//                ArrayList<CcDataWriteEndExcel> chai2 = chai(chai1, ";");//英文
//                ArrayList<CcDataWriteEndExcel> chai3 = chai(chai2, "窗口、");
//                ArrayList<CcDataWriteEndExcel> chai4 = chai(chai3, "窗口 、");
//                ArrayList<CcDataWriteEndExcel> chai5 = chai(chai4, "服务中心、");
//                ArrayList<CcDataWriteEndExcel> chai6 = chai(chai5, "派出所、");

                log.info("数据项:拆分后 {}", result.size());
                EasyExcel.write(_4_1_split_ok_path, CcDataWriteEndExcel.class).sheet("拆分后的数据").doWrite(result);
                EasyExcel.write(_4_1_split_ok_path_中文, CcDataWriteEndExcel.class).sheet("拆分后的数据").doWrite(result);
            }

            private ArrayList<CcDataWriteEndExcel> chai(ArrayList<CcDataWriteEndExcel> allData, String splitStr) {
                ArrayList<CcDataWriteEndExcel> objects = new ArrayList<>();
                for (var a : allData) {
                    String 一级办理地点 = a.get一级办理地点();
                    String 二级办理地点 = a.get二级办理地点();
                    String 办理地点 = StringKit.isNotBlank(一级办理地点) ? 一级办理地点 : 二级办理地点;

                    if (StringKit.isNotBlank(办理地点) && (办理地点.contains(splitStr))) {
                        String originStr = JSONObject.toJSONString(a);
                        String[] split = 办理地点.split(splitStr);

                        for (String str : split) {
                            if (StringKit.isBlank(str)) {
                                //                                System.out.println(JSONObject.toJSONString(a));
                                continue;
                            }
                            CcDataWriteEndExcel ccDataWriteZjExcel = JSONObject.parseObject(originStr, CcDataWriteEndExcel.class);
                            if (StringKit.isNotBlank(一级办理地点)) {
                                ccDataWriteZjExcel.set一级办理地点(str);
                            }
                            if (StringKit.isNotBlank(二级办理地点)) {
                                ccDataWriteZjExcel.set二级办理地点(str);
                            }
                            objects.add(ccDataWriteZjExcel);
                        }

                    } else {
                        objects.add(a);
                    }
                }
                return objects;
            }
        }).sheet().doRead();

    }

    /**
     * 聚合：不拆的 拆失败的 拆完的
     */
    public void _5_sum() throws Exception {
        ArrayList<CcDataWriteEndExcel> allData = new ArrayList<>();
        System.out.println("处理文件 没拆 " + _3_1_0_not_split_path);
        System.out.println("处理文件 存在错误 " + _3_2_split_error_path);
        System.out.println("处理文件 拆分后的 " + _4_1_split_ok_path);


        // 这里默认读取第一个sheet
        EasyExcel.read(_3_1_0_not_split_path, CcDataWriteEndExcel.class, new ReadListener<CcDataWriteEndExcel>() {
            @Override
            public void invoke(CcDataWriteEndExcel data, AnalysisContext context) {
                allData.add(data);
            }

            @SneakyThrows
            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                System.out.println("汇总 _3_1_not_split_path 数据：" + allData.size());


                // 这里默认读取第一个sheet
                EasyExcel.read(_3_2_split_error_path, CcDataWriteEndExcel.class, new ReadListener<CcDataWriteEndExcel>() {
                    @Override
                    public void invoke(CcDataWriteEndExcel data, AnalysisContext context) {
                        allData.add(data);
                    }


                    @SneakyThrows
                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {
                        System.out.println("汇总 _3_2_split_error_path 数据：" + allData.size());


                        // 这里默认读取第一个sheet
                        EasyExcel.read(_4_1_split_ok_path, CcDataWriteEndExcel.class, new ReadListener<CcDataWriteEndExcel>() {
                            @Override
                            public void invoke(CcDataWriteEndExcel data, AnalysisContext context) {
                                allData.add(data);
                            }

                            @SneakyThrows
                            @Override
                            public void doAfterAllAnalysed(AnalysisContext context) {
                                System.out.println("汇总后累计数据：" + allData.size());
                                EasyExcel.write(_5_1_sum_end_path, CcDataWriteEndExcel.class).sheet("最终处理数据").doWrite(allData);
                                EasyExcel.write(_5_1_sum_end_path_中文, CcDataWriteEndExcel.class).sheet("最终处理数据").doWrite(allData);
                            }

                        }).sheet().doRead();


                    }
                }).sheet().doRead();


            }

        }).sheet().doRead();

    }
}
